﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using Autofac;
using Castle.DynamicProxy;
using Hyt.Core.Security;

namespace Hyt.Core
{
    public class UnitOfWork : IUnitOfWork,IDisposable
    {
        /// <summary>
        /// 是否启用事务
        /// </summary>
        private readonly bool _useTransaction = true;
        protected ContainerBuilder Iocbuilder = new ContainerBuilder();
        private bool _iscommited = false;
        private IContainer _container;
        private readonly List<IPartOfWork> _parts = new List<IPartOfWork>();
        private IPrincipal _principal;
        private string _sessionid;

        #region 构造方法 
        public UnitOfWork() {
            Init();
        }
        public UnitOfWork(bool usetransaction)
        {
            this._useTransaction = usetransaction;
            Init();
        }

        protected virtual void Init()
        {
            _principal = Principal.Anonymous;
            BuildContainer(this.Iocbuilder);            
        }
        #endregion

        #region 实现IUnitOfWork
        public void AddPart(IPartOfWork part)
        {
            if (!_parts.Contains(part))
            {
                _parts.Add(part);
            }
        }

        public void Commit()
        {
            if (_iscommited)
            {
                throw new Exception("不可重复提交");
            }

            var commitedparts = new List<IPartOfWork>();
            try
            {
                if (this._useTransaction)
                {
                    using (var trans = new TransactionScope())
                    {
                        foreach (var part in _parts)
                        {
                            part.Commit();
                            commitedparts.Add(part);
                        }
                        trans.Complete();
                    }
                }
                else
                {
                    foreach (var part in _parts)
                    {
                        part.Commit();
                        commitedparts.Add(part);
                    }
                }                
            }
            catch(Exception)
            {
                foreach (var part in commitedparts)
                {
                    part.RollBack();
                }
                throw;
            }
            _iscommited = true;
        }

        public T Get<T>() where T:class
        {
            return getContainer().Resolve<T>();
            if (typeof(IAop).IsAssignableFrom(typeof(T)))
            {
                var iInterceptors = typeof(T).GetCustomAttributes(typeof(InterceptorAttribute), true);
                if (iInterceptors != null && iInterceptors.Any())
                {
                    ProxyGenerator gen = new ProxyGenerator();
                    List<IInterceptor> interceptors = new List<IInterceptor>();
                    foreach (var attr in iInterceptors)
                    {
                        IInterceptor interceptor = ((InterceptorAttribute)attr).GetInterceptor(this);
                        interceptors.Add(interceptor);
                    }
                    T instance = gen.CreateClassProxy<T>(interceptors.ToArray());
                    getContainer().InjectProperties(instance);
                    return instance;
                }
                else
                {
                    return getContainer().Resolve<T>();
                }
            }
            else
            {
                return getContainer().Resolve<T>();
            }
        }

        private IContainer getContainer()
        {
            if (_container == null)
            {
                _container = Iocbuilder.Build();
            }
            return _container;
        }

        protected virtual void BuildContainer(ContainerBuilder builder)
        {
        }

        public void SetIocSetting(IIocSetting iocSetting)
        {
            iocSetting.Register(Iocbuilder,this);
        }

        public IPrincipal GetCurrentPrincipal()
        {
            return _principal;
        }

        public virtual void SetPrincipal(IPrincipal principal)
        {
            this._principal = principal;
        }
        #endregion

        #region 实现IDisposable
        public void Dispose()
        {
            if (_container != null)
            {
                _container.Dispose();
            }
            //try
            //{
            //    if (!_iscommited)
            //    {
            //        Commit();
            //    }
            //}
            //catch (Exception e)
            //{
            //    throw e;
            //}
            //finally
            //{
            //    if (_container != null)
            //    {
            //        _container.Dispose();
            //    }
            //}
        }
        #endregion

        public void Inject<T>(T model) where T : class
        {
            getContainer().InjectProperties(model);
        }
        
        public object Get(Type type)
        {
            return getContainer().Resolve(type);
            //if (typeof(IAop).IsAssignableFrom(type))
            //{
            //    var iInterceptors = type.GetCustomAttributes(typeof(InterceptorAttribute), true);
            //    if (iInterceptors != null && iInterceptors.Any())
            //    {
            //        ProxyGenerator gen = new ProxyGenerator();
            //        List<IInterceptor> interceptors = new List<IInterceptor>();
            //        foreach (var attr in iInterceptors)
            //        {
            //            IInterceptor interceptor = ((InterceptorAttribute)attr).GetInterceptor(this);
            //            interceptors.Add(interceptor);
            //        }
            //        object instance = gen.CreateClassProxy(type, interceptors.ToArray());
            //        //T instance = gen.CreateClassProxy<T>(interceptors.ToArray());
            //        getContainer().InjectProperties(instance);
            //        return instance;
            //    }
            //    else
            //    {
            //        return getContainer().Resolve(type);
            //    }
            //}
            //else
            //{
            //    return getContainer().Resolve(type);
            //}
        }


        public string GetSessionId()
        {
            return _sessionid;
        }

        public void SetSessionId(string sessionid)
        {
            _sessionid = sessionid;
        }
    }
}
